package com.jweb.framework.core.support;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionOperations;
import com.jweb.framework.core.ActionHolder;
import com.jweb.framework.core.Context;
import com.jweb.framework.core.CoreException;
import com.jweb.framework.core.CoreRuntimeException;
import com.jweb.framework.core.CoreSuperException;
import com.jweb.framework.core.EmptyAction;
import com.jweb.framework.core.RuntimeSuperException;


public class Utils {
	
	static class InnerRuntimeException extends RuntimeException{
		private static final long serialVersionUID = -71119947659511118L;
		
		InnerRuntimeException(Throwable throwable){
			super(throwable);
		}
	}
	
	public static boolean shouldLogging(Throwable t){
		if(t instanceof CoreSuperException){
			return !((CoreSuperException)t).isAlreadyLogged() ;
		}
		if(t instanceof RuntimeSuperException){
			return !((RuntimeSuperException)t).isAlreadLogged();
		}
		
		return true ;
	}
	
	public static void runInTx(TransactionOperations transactionOperations , Object action , String methodName , Context context) throws CoreException , CoreRuntimeException {
		
		try {
			
			Method method = action.getClass().getMethod(methodName, new Class[]{Context.class});
			
			runInTx(transactionOperations , action , method , context) ;
		} catch (NoSuchMethodException e) {
			throw new CoreRuntimeException("JAVACO0003" , "no_method_found" , e);
		}
		
	}
	
	
	public static void runInTx(TransactionOperations transactionOperations , final Object action , final Method method , final Context context) throws CoreException , CoreRuntimeException {
		
		if(!method.isAccessible()){
			method.setAccessible(true);
		}
		try {
			
			transactionOperations.execute(new TransactionCallback() {

				public Object doInTransaction(TransactionStatus status) {
					
					try {
						return method.invoke(action , new Object[]{context});
					} catch (InvocationTargetException e) {
						throw new InnerRuntimeException(e.getTargetException());
					}
					catch(IllegalAccessException e){
						throw new InnerRuntimeException(e) ;
					}
				}
			});
			
		} catch (Throwable throwable) {
			if(throwable instanceof InnerRuntimeException){
				throwable = throwable.getCause();
			}
			if(throwable instanceof Error){
				throw (Error)throwable ;
			}
			if(throwable instanceof CoreRuntimeException){
				throw (CoreRuntimeException)throwable ;
			}
			if(throwable instanceof CoreException){
				throw (CoreException)throwable ;
			}
			else {
				CoreException ce = new CoreException("JAVACO0004" , throwable);
				ce.setWrapped(true);
				throw ce ;
			}
		}
		
	}
	
	public static void execute(final Context context , final List list , TransactionOperations transactionOperations) throws CoreException , CoreRuntimeException {
		
		if(transactionOperations == null) {
			execute(context , list);
		}
		else {
			try {
				
				transactionOperations.execute(new TransactionCallback() {

					public Object doInTransaction(TransactionStatus status) {
						
						try {
							Utils.execute(context , list) ;
						} catch (CoreRuntimeException e) {
							throw e ;
						} catch (CoreException e){
							throw new InnerRuntimeException(e);
						}
						
						return null;
					}
					
				});
				
			} catch (Throwable throwable) {
				if(throwable instanceof Error){
					throw (Error)throwable ;
				}
				if(throwable instanceof CoreRuntimeException){
					throw (CoreRuntimeException)throwable ;
				}
				if(throwable instanceof CoreException){
					throw (CoreException)throwable ;
				}
				else {
					CoreException ce = new CoreException("JAVACO006" , throwable);
					context.setException(ce);
					ce.setWrapped(true);
					throw ce ;
				}
			}
		}
		
	}
	
private static void execute(Context context , List list) throws CoreException , CoreRuntimeException {
		
		for(Iterator it = list.iterator() ; it.hasNext() ;){
			
			ActionHolder actionHolder = (ActionHolder) it.next() ;
			
			if(actionHolder.getJservice().getClass() == EmptyAction.class){
				List actionList = context.getProcess().findActions(actionHolder.getName());
				if((actionList == null) || (actionList.isEmpty())){
					EmptyAction emptyAction = (EmptyAction) actionHolder.getJservice();
					if(emptyAction.isPlaceHolder()){
						throw new CoreRuntimeException("JAVACO0005" , "empty_jkservice_placeholder");
					}
				}
				else {
					for(Iterator it2 = actionList.iterator() ; it2.hasNext() ;){
						ActionHolder actionHodler2 = (ActionHolder) it2.next();
						if(actionHodler2.getJservice().getClass() != EmptyAction.class){
							actionHodler2.setThrowNoSuchMethodException(actionHolder.isThrowNoSuchMethodException());
							if(actionHolder.getOperations()!=null && actionHodler2.getOperations()==null){
								actionHodler2.setOperations(actionHolder.getOperations());
							}
							actionHodler2.execute(context);
						}
					}
				}
			}
			else {
				actionHolder.execute(context);
			}
		}
	}
	
}
